package hu.myai.model;

/**
 * It is a line value object.<br>
 * Two points define a line OR<br>
 * One point and an angle
 * 
 * @author bozbalint
 * 
 * */
public class TrendLineVO {

	/**
	 * If any kind of compare it is the reference. It can be any value, does not
	 * matter, but it have to has value.
	 * */
	private static final double xReferenceValue = 5;

	/**
	 * reference time, X value
	 * */
	private double x;

	/**
	 * The reference value, Y value
	 * */
	private double y;

	/**
	 * The angle of the line
	 * */
	private double tangens;

	/**
	 * 
	 * */
	private int touch = 0;

	/**
	 * Set a line with two points. The order of the points is irrelevant. Value
	 * object will store the latest coordinate and the tangent to the line. The
	 * earlier coordinate and the angle will be stored.
	 * */
	public TrendLineVO(double y1, double x1, double y2, double x2) {
		init(y1, x1, y2, x2);
	}

	public TrendLineVO(PointVO point, double y2, double x2) {
		init(point.getY(), point.getX(), y2, x2);
	}

	public TrendLineVO(PointVO point1, PointVO point2) {
		init(point1.getY(), point1.getX(), point2.getY(), point2.getX());
	}

	/**
	 * Set a line with a point and a tangens of an angle.
	 * */
	public TrendLineVO(double y, double x, double tangens) {
		this.x = x;
		this.y = y;

		this.tangens = tangens;
	}

	private void init(double y1, double x1, double y2, double x2) {
		x = x1 < x2 ? x1 : x2;
		y = x1 < x2 ? y1 : y2;

		double xRef = x1 < x2 ? x2 : x1;
		double yRef = x1 < x2 ? y2 : y1;

		if (x1 == x2) {
			throw new RuntimeException("It is not a valid trend line. It is vertical: " + this.toString());
		} else
			tangens = (y - yRef) / (x - xRef);
	}

	/**
	 * @return the touch
	 */
	public int getTouch() {
		return touch;
	}

	/**
	 * @param touch
	 *            the touch to set
	 */
	public void increaseTouch() {
		touch += 1;
	}

	/**
	 * return the X coordinate of the line in case of Y
	 * */
	public double getX(double y) {
		return (y - this.y) / tangens + x;
	}

	/**
	 * return the Y coordinate of the line in case of X
	 * */
	public double getY(double x) {
		return (x - this.x) * tangens + y;
	}

	/**
	 * return the Y projecton of the point and the line distance. It is positive
	 * if the point is below the line.
	 * */
	public double getDistanceY(double y, double x) {
		return getY(x) - y;
	}

	/**
	 * return the X projecton of the point and the line distance
	 * */
	public double getDistanceX(double y, double x) {
		return getX(y) - x;
	}

	/**
	 * @return the tangens
	 */
	public double getTangens() {
		return tangens;
	}

	/**
	 * returns the timestamp when the trend line was started
	 * */
	public double getInitDate(){
		return this.x;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		long temp;
		temp = Double.doubleToLongBits(tangens);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		temp = Double.doubleToLongBits(getY(xReferenceValue));
		result = prime * result + (int) (temp ^ (temp >>> 32));
		return result;
	}

	/**
	 * Two trendlines are equal if they are closer than 0.3%
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;

		TrendLineVO other = (TrendLineVO) obj;
		if (Double.doubleToLongBits(tangens) != Double.doubleToLongBits(other.tangens))
			return false;
		if (Math.abs(getY(other.x) - other.y) > 0.003)
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "[time=" + x + ",y=" + y + ",tg=" + tangens + "]";
	}
}
